import PySpin
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
import enum

system = None
cam_list = None

def initSystem():
    global system,cam_list
    system = PySpin.System.GetInstance()
    cam_list = system.GetCameras()
    num_cam = cam_list.GetSize()

    if num_cam <= 0:

        cam_list.Clear()
        system.ReleaseInstance()
        raise PySpin.SpinnakerException('Not enough camera')

    return num_cam

def deinitSystem():
    global system, cam_list
    if cam_list is not None:
        cam_list.Clear()
    if system is not None:
        system.ReleaseInstance()

class TriggerType(enum.Enum):
    NONE = 0
    SOFTWARE = 1
    HARDWARE = 2

def configure_custom_image_settings(cam):
    nodemap = cam.GetNodeMap()
    """
    设置相机，包括偏移，宽度，高度和像素模式，这个设置必须在BeginAcquisition（）前面，否则它们将只是只读的模式，
    同时需要注意的是，他们是实时改变的，所以要注意设置偏移量和高度宽度的顺序
    Configures a number of settings on the camera including offsets  X and Y, width,
    height, and pixel format. These settings must be applied before BeginAcquisition()
    is called; otherwise, they will be read only. Also, it is important to note that
    settings are applied immediately. This means if you plan to reduce the width and
    move the x offset accordingly, you need to apply such changes in the appropriate order.
    """
    print('\n*** CONFIGURING CUSTOM IMAGE SETTINGS *** \n')

    try:
        result = True

        # Apply mono 8 pixel format
        #设置图片为mono8像素
        node_pixel_format = PySpin.CEnumerationPtr(nodemap.GetNode('PixelFormat'))
        if PySpin.IsAvailable(node_pixel_format) and PySpin.IsWritable(node_pixel_format):

            # Retrieve the desired entry node from the enumeration node
            node_pixel_format_mono8 = PySpin.CEnumEntryPtr(node_pixel_format.GetEntryByName('Mono8'))
            if PySpin.IsAvailable(node_pixel_format_mono8) and PySpin.IsReadable(node_pixel_format_mono8):

                # Retrieve the integer value from the entry node
                pixel_format_mono8 = node_pixel_format_mono8.GetValue()

                # Set integer as new value for enumeration node
                node_pixel_format.SetIntValue(pixel_format_mono8)

                print('Pixel format set to %s...' % node_pixel_format.GetCurrentEntry().GetSymbolic())

            else:
                print('Pixel format mono 8 not available...')

        else:
            print('Pixel format not available...')

        # Apply minimum to offset X
        #设置X轴偏移量
        node_offset_x = PySpin.CIntegerPtr(nodemap.GetNode('OffsetX'))
        # print(node_offset_x.GetDisplayName())
        if PySpin.IsAvailable(node_offset_x) and PySpin.IsWritable(node_offset_x):
            print(type(node_offset_x.GetMin()))
            node_offset_x.SetValue(node_offset_x.GetMin())
            print('Offset X set to %i...%i' % (node_offset_x.GetMin(), node_offset_x.GetMax()))

        else:
            print('Offset X not available...')

        # Apply minimum to offset Y
        #设置Y轴的偏移量
        node_offset_y = PySpin.CIntegerPtr(nodemap.GetNode('OffsetY'))
        if PySpin.IsAvailable(node_offset_y) and PySpin.IsWritable(node_offset_y):

            node_offset_y.SetValue(node_offset_y.GetMin())
            print('Offset Y set to %i...' % node_offset_y.GetMin())

        else:
            print('Offset Y not available...')

        # Set maximum width
        #设置宽度
        node_width = PySpin.CIntegerPtr(nodemap.GetNode('Width'))
        if PySpin.IsAvailable(node_width) and PySpin.IsWritable(node_width):

            width_to_set = int(node_width.GetMax()*0.5)
            node_width.SetValue(width_to_set)
            print('Width set to %i...' % node_width.GetValue())

        else:
            print('Width not available...')

        # Set maximum height
        #设置高度
        node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height'))
        if PySpin.IsAvailable(node_height) and PySpin.IsWritable(node_height):

            height_to_set = int(node_height.GetMax()*0.5)

            node_height.SetValue(height_to_set)
            print('Height set to %i...' % node_height.GetValue())

        else:
            print('Height not available...')

    except PySpin.SpinnakerException as ex:
        print('Error: %s' % ex)
        return False

    return result

class Cam(QtCore.QObject, PySpin.ImageEventHandler):
    cameraObject = None
    imageEventHandler = None
    triggerType = TriggerType.NONE

    # pyqt自定义信号
    imageArrived = QtCore.pyqtSignal(np.ndarray, int)

    def __init__(self):
        global system, cam_list
        super().__init__()
        self.cam = cam_list.GetByIndex(0)
        print('2')
        self.cam.Init()
        self.cam.RegisterEventHandler(self)
        # self.setTrigger(self.triggerType)
        self.cam.AcquisitionMode.SetValue(PySpin.AcquisitionMode_Continuous)
        configure_custom_image_settings(self.cam)
        self.imageCount = 0
        print('init')



    def OnImageEvent(self, image):
        if image.IsIncomplete():
            print('Image incomplete with image status %i...' % image.GetImageStatus())
        else:
            image_converted = image.Convert(PySpin.PixelFormat_RGB8,
                                                   PySpin.NEAREST_NEIGHBOR)  # PySpin.HQ_LINEAR)

            image_array = image_converted.GetNDArray()
            self.imageCount += 1
            self.imageArrived.emit(image_array, self.imageCount)  #将图片发射给GUI

    def enableAcquisition(self):
        self.cam.BeginAcquisition()



